/*
 * Created on 3.7.2006
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author tschroderus
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package fileReader.demo.reader;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Point2D;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;


/**
 * In this class user interface is defined. We have defined all the methods to create the
 * interface and to interact with it like button and mouse events. We have separated clearly
 * the user interface from the rest of the application.
 */

public class Simulator extends JFrame {

	private static final long serialVersionUID = 1L;
	
	/** Visual Components**/
	private JPanel jContentPane = null;
	private JMenuBar MenuBar = null;
	private JMenu SystemMenu = null;
	private JMenu FileMenu = null;
	private JMenu ToolsMenu = null;
	private JMenu HelpMenu = null;
	private JMenuItem ExitMenuItem = null;
	private JMenuItem TraceMenuItem = null; // Build + Djikstra
	private JMenuItem BuildMenuItem = null; // Only Build
	private JCheckBoxMenuItem AddPointMenuItem = null;
	private JCheckBoxMenuItem AddPanMenuItem = null;
	private JCheckBoxMenuItem EnableZoomMenuItem = null;
	
	private JMenuItem OpenMenuItem = null;
	private JMenuItem AboutMenuItem = null;
	private JMenuItem ResetPointsMenuItem = null;
	
	private JMenu ZoomMenu = null;
	private JMenuItem ZoomInMenuItem = null;
	private JMenuItem ZoomOutMenuItem = null;

	
	//Accuarcy
	private JMenu AccuracyMenu = null;
	private JCheckBoxMenuItem accuracy1000 = null;
	private JCheckBoxMenuItem accuracy5000 = null;
	private JCheckBoxMenuItem accuracy10000 = null;
	private JCheckBoxMenuItem accuracy15000 = null;
	private JCheckBoxMenuItem accuracy20000 = null;
	
	//Layers
	private JMenu LayerMenu = null;
	private JCheckBoxMenuItem depthArea = new JCheckBoxMenuItem();	//deptharea
	private JCheckBoxMenuItem depthContour = new JCheckBoxMenuItem();	//depthcontour
	private JCheckBoxMenuItem signsound = new JCheckBoxMenuItem();//signsound
	private JCheckBoxMenuItem rocks = new JCheckBoxMenuItem(); //rocks
	private JCheckBoxMenuItem coastline = new JCheckBoxMenuItem(); //coastline
	private JCheckBoxMenuItem text = new JCheckBoxMenuItem();	//text
	private JCheckBoxMenuItem generarea = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem navigline = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem pipeline = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem limit1 = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem limit2 = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem fway = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem river = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem roadnrailw = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem obstruct = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem harbour = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem natseabed = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem bridge = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem leadinglne = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem building = new JCheckBoxMenuItem();
	private JCheckBoxMenuItem builtupare = new JCheckBoxMenuItem();
	private JMenuItem ResetSelections = new JCheckBoxMenuItem();
	private JMenuItem SelectAll = new JCheckBoxMenuItem();

	
	private JMenu DepthMenu = null;
	private JCheckBoxMenuItem depthAll = null;	//all
	private JCheckBoxMenuItem depthTen = null;	//10m
	private JCheckBoxMenuItem depthTwenty = null;	//20m
	private JCheckBoxMenuItem depthFifty = null;//50m
	
	/** Map Object **/
	private Map map = null;
	private EsriFileReader fileReader = null;
	private Simulator simulator = null; //this is needed on mouse actions
	private int accuracyItem=5; //What map accuracy is selected
	
	private JLabel Status = null;
	
	/** VisibilityGraph **/
	VisibilityGraph vgraph;
	
	private String mapPath=""; //path of the map
	private static int selectedDepth=10;
	
	/** Window size variables **/
	
	private static boolean errorMessage=false;
	/**
     * A panel derived from a JPanel where the body parts are drawn.
     * The JPanel's paintComponent() method is overriden so that the gallows is
     * automatically drawn when the panel is repainted.
     */
    private JPanel Canvas = new JPanel() {
    	private static final long serialVersionUID = 1L;
    
        public void paintComponent(Graphics g) { 
        	// called whenever the panel is
            // repainted.  The graphics context g is supplied by the GUI
            // component that contains this JPanel.
        	//g.setColor(new Color(255,255,153));
            super.paintComponent(g);   	// do whatever usually is done
            
            map.DrawMap(g);
            map.DrawVGraph(g);
        }
    };

	/**
	 * Constructor for the class Simulator.
	 * Creates a new map object and then initializes the user interface.
	 */
	public Simulator() {
		super();
		simulator=this;
		map = new Map(this);
		initialize();
	}

	//FIXME - metodi lisätty
	public Map getMap() {
		return this.map;
	}
	
	
	
	
	/**
	 * Initializes the user interface. Sets also the user interfaces size
	 * into variables size_x and size_y.
	 */
	private void initialize() {
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setJMenuBar(getJJMenuBar());
	
		this.pack(); //let us maximize the window
		this.setExtendedState(Frame.MAXIMIZED_BOTH);		
		this.setContentPane(getJContentPane());
		this.setTitle("UpWind2 Simulator -v.0.3");

		
		// create and add mouse listener to mousePanel 
	    MouseListener mouseListener = new MouseListener();
	    MouseWheelE mouseWheel = new MouseWheelE();
	    Canvas.addMouseListener(mouseListener);
	    Canvas.addMouseWheelListener(mouseWheel);

	    
	}

	/**
	 * Returns contentPane.
	 * If contentPane is not yet created then 
	 * initializes it and adds status to contentPane.
	 * @return jContentPane contentpane.
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			Status = new JLabel();
			Status.setText("Status: OK!");
			jContentPane = new JPanel();
			jContentPane.setLayout(new BorderLayout());
			jContentPane.add(Canvas, java.awt.BorderLayout.CENTER);
			jContentPane.add(Status, java.awt.BorderLayout.SOUTH);
		}
		return jContentPane;
	}
	
	
	/**
	 * Retuns menuBar. If MenuBar is not yet created then
	 * creates menubar. In this method every menu option
	 * is being added to the menuBar.
	 * @return MenuBar menubar.
	 */
	private JMenuBar getJJMenuBar() {
		if (MenuBar == null) {
			MenuBar = new JMenuBar();
			MenuBar.add(getFileMenu());
			MenuBar.add(getSystemMenu());
			MenuBar.add(getToolsMenu());
			MenuBar.add(getHelpMenu());
		}
		return MenuBar;
	}

	/**
	 * Retuns SystemMenu. If SystemMenu is not yet created then
	 * creates SystemMenu. In this method every System menu item 
	 * is being added to System menu.
	 * @return SystemMenu systemMenu.
	 */
	private JMenu getSystemMenu() {
		if (SystemMenu == null) {
			SystemMenu = new JMenu();
			SystemMenu.setText("System");
			SystemMenu.setEnabled(false);
			SystemMenu.add(getTraceMenuItem()); //Show only optimal paths
			SystemMenu.add(getBuildMenuItem()); //Show only VGraph
			
			//menu items
			SystemMenu.add(getAddPointCheckBoxMenuItem()); //When is checked is possible to add control points
			SystemMenu.add(getAddPanCheckBoxMenuItem()); //When is checked is possible to add control points
			SystemMenu.add(getEnableZoomMenuItem()); //When is checked is possible to add control points
		}
		return SystemMenu;
	}
	
	/**
	 * Creates a menu item "Add Control Point [left button]".
	 * This menu item belongs to System menu.
	 * @return AddPointMenuItem item.
	 */
	private JCheckBoxMenuItem getAddPointCheckBoxMenuItem() {
		if (AddPointMenuItem == null) {
			AddPointMenuItem = new JCheckBoxMenuItem("Add Control Point [left button]",true);
		}
		return AddPointMenuItem;
	}
	
	/**
	 * Creates a menu item "Enable Pan [left button drag&drop]".
	 * This menu item belongs to System menu.
	 * @return AddPanMenuItem item.
	 */
	private JCheckBoxMenuItem getAddPanCheckBoxMenuItem() {
		if (AddPanMenuItem == null) {
			AddPanMenuItem = new JCheckBoxMenuItem("Enable Pan [left button drag&drop]",true);
		}
		return AddPanMenuItem;
	}
	
	/**
	 * Creates a menu item "Enable ZOOM [scroll wheel]".
	 * This menu item belongs to System menu.
	 * @return EnableZoomMenuItem item.
	 */
	private JCheckBoxMenuItem getEnableZoomMenuItem() {
		if (EnableZoomMenuItem == null) {
			EnableZoomMenuItem = new JCheckBoxMenuItem("Enable ZOOM [scroll wheel]",true);
		}
		return EnableZoomMenuItem;
	}
	
	/**
	 * Retuns FileMenu. If FileMenu is not yet created then
	 * creates FileMenu. In this method every File menu item 
	 * is being added to File menu.
	 * @return FileMenu fileMenu.
	 */
	private JMenu getFileMenu() {
		if (FileMenu == null) {
			FileMenu = new JMenu();
			FileMenu.setText("File");
			
			//menu items
			FileMenu.add(getOpenMenuItem());  // Opens the Map Files (txt)
			FileMenu.add(getResetPointsMenuItem()); 
			FileMenu.add(getExitMenuItem());  // Exit button
		}
		return FileMenu;
	}
	
	/**
	 * This method makes a tools menu.
	 * @return ToolsMenu
	 */
	
	private JMenu getToolsMenu() {
		if (ToolsMenu == null) {
			ToolsMenu = new JMenu();
			ToolsMenu.setText("Tools");
			ToolsMenu.setEnabled(false);
			//menu items
			ToolsMenu.add(getZoomMenu()); 
			ToolsMenu.add(new JSeparator());
			ToolsMenu.add(getAccuracyMenu());
			ToolsMenu.add(getLayerMenu());
			ToolsMenu.add(getDepthMenu());
			
		}
		return ToolsMenu;
	}
	
	/**
	 * This method makes a depth menu.
	 * @return DepthMenu
	 */
	private JMenuItem getDepthMenu() {
		if (DepthMenu == null) {
			DepthMenu = new JMenu();
			DepthMenu.setText("Depth");
			
			DepthMenu.add(getDepthAllMenuItem());
			DepthMenu.add(getDepthTenMenuItem());
			DepthMenu.add(getDepthTwentyMenuItem());
			DepthMenu.add(getDepthFiftyMenuItem());
		}
		return DepthMenu;
	}
	
	
	/**
	 * Here is added a depth area choice to the depth menu
	 * @return DepthOne first depth choice
	 */
	private JMenuItem getDepthAllMenuItem() {
		if (depthAll == null) {
			depthAll = new JCheckBoxMenuItem();
			depthAll.setText("All");
			
			depthAll.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					selectedDepth=0;
					depthFifty.setSelected(false);
					depthTwenty.setSelected(false);
					depthTen.setSelected(false);
					Canvas.repaint();
				}	
			});
		}
		return depthAll;
	}
	
	/**
	 * Here is added a depth area choice to the depth menu
	 * @return DepthOne first depth choice
	 */
	private JMenuItem getDepthTenMenuItem() {
		if (depthTen == null) {
			depthTen = new JCheckBoxMenuItem();
			depthTen.setText("10 meters");
			
			depthTen.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					selectedDepth=10;
					depthAll.setSelected(false);
					depthFifty.setSelected(false);
					depthTwenty.setSelected(false);
					Canvas.repaint();
				}	
			});
		}
		return depthTen;
	}

	/**
	 * Here is added a depth area choice to the depth menu
	 * @return DepthTwo second depth choice
	 */
	private JMenuItem getDepthTwentyMenuItem() {
		if (depthTwenty == null) {
			depthTwenty = new JCheckBoxMenuItem();
			depthTwenty.setText("20 meters");
			
			depthTwenty.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					selectedDepth=20;
					depthAll.setSelected(false);
					depthTen.setSelected(false);
					depthFifty.setSelected(false);
					Canvas.repaint();
				}	
			});
		}
		return depthTwenty;
	}

	/**
	 * Here is added a depth area choice to the depth menu
	 * @return DepthThree Third depth choice
	 */
	private JMenuItem getDepthFiftyMenuItem() {
		if (depthFifty == null) {
			depthFifty = new JCheckBoxMenuItem();
			depthFifty.setText("50 meters");
						
			depthFifty.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					selectedDepth=50;
					depthAll.setSelected(false);
					depthTen.setSelected(false);
					depthTwenty.setSelected(false);
					Canvas.repaint();
				}	
			});
		}
		return depthFifty;
	}


	/**
	 * This method makes a layer menu.
	 * @return LayerMenu
	 */
	private JMenuItem getLayerMenu() {
		if (LayerMenu == null) {
			LayerMenu = new JMenu();
			LayerMenu.setText("Layers");
			
			LayerMenu.add(getSelectAllMenuItem());
			LayerMenu.add(getResetSelectionsMenuItem());
			LayerMenu.add(new JSeparator());
			LayerMenu.add(getLayerMenuItem(depthArea, "Deptharea"));//getDepthareaMenuItem());
			LayerMenu.add(getLayerMenuItem(depthContour, "Depthcontour"));
			LayerMenu.add(getLayerMenuItem(signsound, "Signsound"));
			LayerMenu.add(getLayerMenuItem(rocks, "Rocks"));
			LayerMenu.add(getLayerMenuItem(coastline, "Coastline"));
			LayerMenu.add(getLayerMenuItem(text, "Text"));
			LayerMenu.add(getLayerMenuItem(generarea, "Generarea"));
			LayerMenu.add(getLayerMenuItem(navigline, "Navigline"));
			LayerMenu.add(getLayerMenuItem(pipeline, "Pipeline"));
			LayerMenu.add(getLayerMenuItem(limit1, "Limit 1"));
			LayerMenu.add(getLayerMenuItem(limit2, "Limit 2"));
			LayerMenu.add(getLayerMenuItem(fway, "Fway"));
			LayerMenu.add(getLayerMenuItem(river, "River"));
			LayerMenu.add(getLayerMenuItem(roadnrailw, "RoadNRailw"));
			LayerMenu.add(getLayerMenuItem(obstruct, "Obstruct"));
			LayerMenu.add(getLayerMenuItem(harbour, "Harbour"));
			LayerMenu.add(getLayerMenuItem(natseabed, "Natseabed"));
			LayerMenu.add(getLayerMenuItem(bridge, "Bridge"));
			LayerMenu.add(getLayerMenuItem(leadinglne, "LeadingLne"));
			LayerMenu.add(getLayerMenuItem(building, "Building"));
			LayerMenu.add(getLayerMenuItem(builtupare, "Builtupare"));
		}
		return LayerMenu;
	}


	private JMenuItem getResetSelectionsMenuItem() {
		ResetSelections=new JMenuItem();
		ResetSelections.setText("Reset all");
		ResetSelections.setEnabled(false);
		
		ResetSelections.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				resetAllMenuItems(false);
				Canvas.repaint();
			}	
		});
		
		return ResetSelections;
	}
	
	
	private JMenuItem getSelectAllMenuItem() {
		SelectAll=new JMenuItem();
		SelectAll.setText("Select all");
		SelectAll.setEnabled(true);
		
		SelectAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				resetAllMenuItems(true);
				Canvas.repaint();
			}	
		});
		
		return SelectAll;
	}

	private void resetAllMenuItems(boolean status){
		depthArea.setSelected(status);
		depthContour.setSelected(status);
		signsound.setSelected(status);
		rocks.setSelected(status);
		coastline.setSelected(status);
		text.setSelected(status);
		generarea.setSelected(status);
		navigline.setSelected(status);
		pipeline.setSelected(status);
		limit1.setSelected(status);
		limit2.setSelected(status);
		fway.setSelected(status);
		river.setSelected(status);
		roadnrailw.setSelected(status);
		obstruct.setSelected(status);
		harbour.setSelected(status);
		natseabed.setSelected(status);
		bridge.setSelected(status);
		leadinglne.setSelected(status);
		building.setSelected(status);
		builtupare.setSelected(status);
		SelectAll.setEnabled(status);
		ResetSelections.setEnabled(status);
	}

	

	private JMenuItem getLayerMenuItem(JCheckBoxMenuItem layerMenu, String layer) {
			layerMenu.setText(layer);
			
			layerMenu.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					Canvas.repaint();
				}	
			});
		return layerMenu;
	}
	
	
	/**
	 * makes the zoom menu.
	 * @return ZoomMenu
	 */
	private JMenuItem getZoomMenu() {
		if (ZoomMenu == null) {
			ZoomMenu = new JMenu();
			ZoomMenu.setText("Zoom");
			ZoomMenu.add(getZoomInMenuItem());
			ZoomMenu.add(getZoomOutMenuItem());
		}
		return ZoomMenu;
	}
	
	/**
	 * zoom in option
	 * @return ZoomInMenuItem item for zoom menu
	 */
	private JMenuItem getZoomInMenuItem() {
		if (ZoomInMenuItem == null) {
			ZoomInMenuItem = new JMenuItem();
			ZoomInMenuItem.setText("In");
			
			ZoomInMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
	    			map.setZoom(map.getZoom()+0.1);//zoom 10%
	    			Status.setText("Current Zoom: "+(int)((map.getZoom()-1)*100)+"%");
				}	
			});
		}
		return ZoomInMenuItem;
	}

	/**
	 * zoom out option
	 * @return ZoomOutMenuItem item for zoom menu
	 */
	private JMenuItem getZoomOutMenuItem() {
		if (ZoomOutMenuItem == null) {
			ZoomOutMenuItem = new JMenuItem();
			ZoomOutMenuItem.setText("Out");
			
			ZoomOutMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
	    			map.setZoom(map.getZoom()-0.1);//zoom -10%
	    			Status.setText("Zoom - ### Current Zoom: "+(int)((map.getZoom()-1)*100)+"%");
				}	
			});
		}
		return ZoomOutMenuItem;
	}
		
	/**
	 * makes the zoom menu.
	 * @return ZoomMenu
	 */
	private JMenuItem getAccuracyMenu() {
		if (AccuracyMenu == null) {
			AccuracyMenu = new JMenu();
			AccuracyMenu.setText("Accuracy");
			AccuracyMenu.add(getAccuracy1000MenuItem());
			AccuracyMenu.add(getAccuracy5000MenuItem());
			AccuracyMenu.add(getAccuracy10000MenuItem());
			AccuracyMenu.add(getAccuracy15000MenuItem());
			AccuracyMenu.add(getAccuracy20000MenuItem());
		}
		return AccuracyMenu;
	}
	
	/**
	 * Accuracy selection. This is implemented by using checkboxes.
	 * @return AccuracyOne menu item.
	 */
	
	private JCheckBoxMenuItem getAccuracy1000MenuItem() {
		if (accuracy1000 == null) {
			accuracy1000 = new JCheckBoxMenuItem();
			accuracy1000.setText("1000");
			
			accuracy1000.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					accuracy5000.setSelected(false);
					accuracy10000.setSelected(false);
					accuracy15000.setSelected(false);
					accuracy20000.setSelected(false);
					accuracyItem=1;
					map.reduceData(1000);
					Canvas.repaint();
				}	
			});
		}
		return accuracy1000;
	}

	/**
	 * Accuracy selection. This is implemented by using checkboxes.
	 * Reads the map again if accuracy have been reduced below this accuracy.
	 * @return AccuracyOne menu item.
	 */
	
	private JCheckBoxMenuItem getAccuracy5000MenuItem() {
		if (accuracy5000 == null) {
			accuracy5000 = new JCheckBoxMenuItem();
			accuracy5000.setText("5000");
			
			accuracy5000.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if(accuracyItem<2){
						if(fileReader!=null){
							setHourClassCursor();
							map.CleanMapLayers();
							fileReader.readMap(mapPath, map);
						}	
					}
					accuracy1000.setSelected(false);
					accuracy10000.setSelected(false);
					accuracy15000.setSelected(false);
					accuracy20000.setSelected(false);
					accuracyItem=2;
					map.reduceData(5000);
					Canvas.repaint();
				
				}	
			});
		}
		return accuracy5000;
	}	
	
	/**
	 * Accuracy selection. This is selected as a default.
	 * This is implemented by using checkboxes.
	 * @return AccuracyOne menu item.
	 */
	
	private JCheckBoxMenuItem getAccuracy10000MenuItem() {
		if (accuracy10000 == null) {
			accuracy10000 = new JCheckBoxMenuItem();
			accuracy10000.setText("10000");
			
			accuracy10000.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if(accuracyItem<3){
						if(fileReader!=null){
							setHourClassCursor();
							map.CleanMapLayers();
							fileReader.readMap(mapPath, map);
						}	
					}
					accuracy1000.setSelected(false);
					accuracy5000.setSelected(false);
					accuracy15000.setSelected(false);
					accuracy20000.setSelected(false);
					accuracyItem=3;
					map.reduceData(10000);
					Canvas.repaint();
				}	
			});
		}
		return accuracy10000;
	}

	/**
	 * Accuracy selection. This is implemented by using checkboxes.
	 * @return AccuracyOne menu item.
	 */
	
	private JCheckBoxMenuItem getAccuracy15000MenuItem() {
		if (accuracy15000 == null) {
			accuracy15000 = new JCheckBoxMenuItem();
			accuracy15000.setText("15000");
			
			accuracy15000.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if(accuracyItem<4){
						if(fileReader!=null){
							setHourClassCursor();
							map.CleanMapLayers();
							fileReader.readMap(mapPath, map);
						}	
					}
					accuracy1000.setSelected(false);
					accuracy5000.setSelected(false);
					accuracy10000.setSelected(false);
					accuracy20000.setSelected(false);
					accuracyItem=4;
					map.reduceData(15000);
					Canvas.repaint();
				}	
			});
		}
		return accuracy15000;
	}
	
	/**
	 * Accuracy selection. This is implemented by using checkboxes.
	 * @return AccuracyOne menu item.
	 */
	
	private JCheckBoxMenuItem getAccuracy20000MenuItem() {
		if (accuracy20000 == null) {
			accuracy20000 = new JCheckBoxMenuItem();
			accuracy20000.setText("20000");
			
			accuracy20000.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if(accuracyItem<5){
						if(fileReader!=null){
							setHourClassCursor();
							map.CleanMapLayers();
							fileReader.readMap(mapPath, map);
						}	
					}
					accuracy1000.setSelected(false);
					accuracy5000.setSelected(false);
					accuracy10000.setSelected(false);
					accuracy15000.setSelected(false);
					accuracyItem=5;
					map.reduceData(20000);
					Canvas.repaint();
				}	
			});
		}
		return accuracy20000;
	}

	/**
	 * Creates "Reset map info" menu item. Handles also user events.
	 * @return ResetPointsMenuItem menu item.
	 */
	private JMenuItem getResetPointsMenuItem() {
		if (ResetPointsMenuItem == null) {
			ResetPointsMenuItem = new JMenuItem();
			ResetPointsMenuItem.setText("Reset map info");
			
			ResetPointsMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if(fileReader!=null){
						Status.setText("Map info reseted");
						map.ResetInfo();
						map.CleanMapLayers();
						map.CleanMapInfo();
						ResetMenuOptions();
					}
					Canvas.repaint();
				}
			});
		}
		return ResetPointsMenuItem;
	}
	
	/**
	 * Creates "Open Map File" item into file menu.
	 * Handles also user events. If user opens a map
	 * then calls ap objects OpenMapFile method.
	 * @return OpenMenuItem item.
	 */
	private JMenuItem getOpenMenuItem() {
		
		if (OpenMenuItem == null) {
			OpenMenuItem = new JMenuItem();
			OpenMenuItem.setText("Open Map File");
			
			
			OpenMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					OpenMapFile();
					SystemMenu.setEnabled(true);

					Canvas.setBackground(Color.LIGHT_GRAY);
					Canvas.repaint(); //repaints the map after it has been opened
				}
			});
		}
		return OpenMenuItem;
	}
	
	
	/**
	 * Returns help menu. Also adds items into help menu.
	 * @return HelpMenu item.
	 */
	private JMenu getHelpMenu() {
		if (HelpMenu == null) {
			HelpMenu = new JMenu();
			HelpMenu.setText("Help");
			HelpMenu.add(getAboutMenuItem());
		}
		return HelpMenu;
	}

	/**
	 * Creates exit menu item. 
	 * Handles also user events.
	 * @return ExitMenuItem item.
	 */
	private JMenuItem getExitMenuItem() {
		if (ExitMenuItem == null) {
			ExitMenuItem = new JMenuItem();
			ExitMenuItem.setText("Exit");
			ExitMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					System.exit(0);
				}
			});
		}
		return ExitMenuItem;
	}


	/**
	 * Creates about menu item.
	 * Handles also user events.
	 * @return AboutMenuItem item.
	 */
	private JMenuItem getAboutMenuItem() {
		if (AboutMenuItem == null) {
			AboutMenuItem = new JMenuItem();
			AboutMenuItem.setText("About");
		
			AboutMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed( ActionEvent event )
				{
					
					URL url = this.getClass().getResource("FileWindlogo01.jpg");
					Image img = Toolkit.getDefaultToolkit().getImage(url);
					
					JLabel jLabel = new JLabel(new ImageIcon(img));
					JDialog jDialog = new JDialog(Simulator.this, "About", true); //.show
					jDialog.setContentPane(jLabel);
					jDialog.setSize(300,270);
					jDialog.setResizable(false);
					jDialog.setVisible(true);
						
				}
				
				
			});
		}
		return AboutMenuItem;
	}
	
	/**
	 * This creates "Show Graph" menu item. 
	 * Handles also user events. When menu item
	 * is choosed then method calls calculateGrap method
	 * to calculate.
	 * @return BuildMenuItem item.
	 */
	private JMenuItem getBuildMenuItem() {
		if (BuildMenuItem == null) {
			BuildMenuItem = new JMenuItem();
			BuildMenuItem.setText("Show Graph");
			
			BuildMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {    
					map.ShowVGraph=true;	
					map.ShowPaths=false;
					map.CalculateGraph();
					//ok! Everything has been calculated! let's draw!
					Status.setText("Visibility Graph Built");
					Canvas.repaint();
				}
			});
		}
		return BuildMenuItem;
	}
	
	/**
	 * This creates a "Trace routes" menu item.
	 * Also user events are catched in this method.
	 * @return TraceMenuItem item.
	 */
	private JMenuItem getTraceMenuItem() {
		if (TraceMenuItem == null) {
			TraceMenuItem = new JMenuItem();
			TraceMenuItem.setText("Trace routes");
			
			TraceMenuItem.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {    
					
					if(map.getControlPoint().data.size()>=2){
						map.ShowVGraph=false;
						map.ShowPaths=true;				
						map.CalculateGraph();
						//ok! Everything has been calculated! let's draw!
						Status.setText("Paths found: "+map.getPaths().size());
						Canvas.repaint();
					}else{
						Status.setText("ERROR: At least 2 control points are needed to trace path.");
					}
				}
			});
		}
		return TraceMenuItem;
	}
	
	/**
	 * Main method. Creates a simulator object.
	 * @param args command line parameters.
	 */
	public static void main(String[] args) {
		Simulator application = new Simulator();
		application.setVisible(true); //.show();
	}
	
	
	
	/**
     * This inner class handles mouse events.
     *
     */
    private class MouseListener extends MouseAdapter
    {
        int x,y;
        double controlX = 0.0;
        double controlY = 0.0;
        // called when mouse is clicked
        public void mouseClicked(MouseEvent e)
        {
                 boolean LetsAdd=AddPointMenuItem.getState();
                 //boolean LetsPan=AddPanMenuItem.getState();
                 boolean inside=false;

                 if(LetsAdd){
                	 	x = e.getX();
                	 	y = e.getY();
                        controlX = (x-map.getX_translation()) / map.getZoom() / ( 1600.0 / (MapLayer.getGlobalMax_x()-MapLayer.getGlobalMin_x())) + MapLayer.getGlobalMin_x(); 
                        controlY = ((y-map.getY_translation())/map.getZoom() - 900.0) / (900.0/ (MapLayer.getGlobalMin_y()-MapLayer.getGlobalMax_y())) + MapLayer.getGlobalMin_y();
                       
                        //System.out.println(controlX + " " + controlY);
                        
                        //Reset variables to force re-calculating and re-drawing
                         map.ResetVars();
                         Point2D v = new Point2D.Double(controlX,controlY);

                         //Add control point if it is outside a polygon.
                         inside=map.AddControlPoint(v);
                         if(!inside)
                        	 Status.setText("ERROR: Operation not allowed - control point inserted 'inside a polygon'.");
                         else
                             Status.setText("OK!: Control point added successfully");

                         Canvas.repaint();
                 }
        }
	    
	    /**
	     * mouse pressed
	     */
	    public void mousePressed(MouseEvent e){	 
	    	 simulator.setHandCursor();
	    	 boolean LetsPan=AddPanMenuItem.getState();
		    
	    	 if(LetsPan){
	    		 x = e.getX(); //gets the point coordinates
	    		 y = e.getY();
	    	 }
	    	 
	    	 
	    }
	    
	    /**
	     * mouse released. This checks that has the pressed coordinate
	     * moved and paints the map.
	     */
	    public void mouseReleased(MouseEvent e){	
	    	 simulator.setNormalCursor();
	    	 boolean LetsPan=AddPanMenuItem.getState();
	    	 
	    	 int x_rel,y_rel;
	    	 int tmpx_translation;
	    	 int tmpy_translation;
	
	    	 if(LetsPan){
	    		 x_rel = e.getX();
	    		 y_rel = e.getY();
	    		 tmpx_translation = x_rel - x;
	    		 tmpy_translation = y_rel - y;
	    		 map.setX_translation(map.getX_translation()+tmpx_translation);
	    		 map.setY_translation(map.getY_translation()+tmpy_translation);
	    	
	    		 Canvas.repaint();
	    	 }
	    	 
	    }
	    
	  }
	
	/**
	 * This inner class handles MouseWheelEvents.
	 *
	 */
	public class MouseWheelE implements MouseWheelListener
	{     
		/**
		 * When a wheel moves on a mouse.
		 */
	    public void mouseWheelMoved(MouseWheelEvent e) {
	      
	    	//this checks that has the user enabled this option from menu
	    	boolean LetsZoom=EnableZoomMenuItem.getState();
			
	    	if(LetsZoom){
	    		int notches = e.getWheelRotation();

	    		if (notches < 0) {
	    			//message = "Mouse wheel moved UP "+ -notches + " notch(es)";
	    			map.setZoom(map.getZoom()+0.1);//zoom 10%
	    			Status.setText("Zoom + ### Current Zoom: "+(int)((map.getZoom()-1)*100+100)+"%");
	    		} else {
	    			//message = "Mouse wheel moved DOWN "+ notches + " notch(es)";
	    			map.setZoom(map.getZoom()-0.1);//zoom -10%
	    			Status.setText("Zoom - ### Current Zoom: "+(int)((map.getZoom()-1)*100+100)+"%");
	    		}
	    		Canvas.repaint();
	    	}
	     }
	  }
	
	
	public boolean isLayerSelected(String layerName) {
		if(layerName.equals("Deptharea")){
			return depthArea.isSelected();
		}else if(layerName.equals("Depthcontour")){
			return depthContour.isSelected();
		}else if(layerName.equals("Signsound")){
			return signsound.isSelected();
		}else if(layerName.equals("Rocks")){
			return rocks.isSelected();
		}else if(layerName.equals("Coastline")){
			return coastline.isSelected();
		}else if(layerName.equals("Text")){
			return text.isSelected();
		}else if(layerName.equals("Generarea")){
			return generarea.isSelected();
		}else if(layerName.equals("Naviglne")){
			return navigline.isSelected();
		}else if(layerName.equals("Pipeline")){
			return pipeline.isSelected();
		}else if(layerName.equals("LimitL")){
			return limit1.isSelected();
		}else if(layerName.equals("LimitP")){
			return limit2.isSelected();
		}else if(layerName.equals("River")){
			return river.isSelected();
		}else if(layerName.equals("Fwayarea")){
			return fway.isSelected();
		}else if(layerName.equals("Roadnrailw")){
			return roadnrailw.isSelected();
		}else if(layerName.equals("Obstruct")){
			return obstruct.isSelected();
		}else if(layerName.equals("Harbour")){
			return harbour.isSelected();
		}else if(layerName.equals("Natseabed")){
			return natseabed.isSelected();
		}else if(layerName.equals("Bridge")){
			return bridge.isSelected();
		}else if(layerName.equals("Leadinglne")){
			return leadinglne.isSelected();
		}else if(layerName.equals("Building")){
			return building.isSelected();
		}else if(layerName.equals("Builtupare")){
			return builtupare.isSelected();
		}
		return false;
	}
		
	/**
	 * This method handles the open dialog when the map is opened.
	 * Map is loaded by calling LoadMap method.
	 * @param parent parent frame
	 */
	public void OpenMapFile(){
		
		JFileChooser fc;
		//FIXME debuggausta ladataa suroaa maps-kansioon
		fc = new JFileChooser();
		fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		int returnVal = fc.showOpenDialog(this);
		//fc.setAcceptAllFileFilterUsed(false); //false

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			ResetMenuOptions();
			map.CleanMapLayers();
			map.CleanMapInfo();
			errorMessage=false;     

			String path = "";
			path = fc.getSelectedFile().toString()+"//";
			mapPath=path; //saves the map path into mapPath variable used on increasing points
			
			Canvas.repaint();
			
			fileReader = new EsriFileReader();
			
			if(path!=""){
				setHourClassCursor();
				ToolsMenu.setEnabled(true);
				fileReader.readMap(path, map);
			}				
		}
	}

	/**
	 * This method sets all selections to menu.
	 *
	 */
	public void ResetMenuOptions() {
		depthArea.setSelected(true);
		depthContour.setSelected(true);
		signsound.setSelected(true);
		rocks.setSelected(false);
		coastline.setSelected(false);
		text.setSelected(false);
		generarea.setSelected(false);
		navigline.setSelected(false);
		pipeline.setSelected(false);
		limit1.setSelected(false);
		limit2.setSelected(false);
		fway.setSelected(false);
		river.setSelected(false);
		roadnrailw.setSelected(false);
		obstruct.setSelected(false);
		harbour.setSelected(false);
		natseabed.setSelected(false);
		bridge.setSelected(false);
		leadinglne.setSelected(false);
		building.setSelected(false);
		builtupare.setSelected(false);
		
		accuracy1000.setSelected(false);
		accuracy5000.setSelected(false);
		accuracy10000.setSelected(false);
		accuracy15000.setSelected(false);
		accuracy20000.setSelected(true);
		
		depthAll.setSelected(false);
		depthTen.setSelected(true);
		depthTwenty.setSelected(false);
		depthFifty.setSelected(false);
		
		ToolsMenu.setEnabled(false);
		SystemMenu.setEnabled(false);
	}

	
	/**
	 * @return Returns the selectedDepth.
	 */
	public static int getSelectedDepth() {
		return selectedDepth;
	}

	/**
	 * @param selectedDepth The selectedDepth to set.
	 */
	public static void setSelectedDepth(int selectedDepth) {
		Simulator.selectedDepth = selectedDepth;
	}

	/**
	 * Prints out an errormessage
	 * @param string error text
	 */
	public static void errorMsg(String msg) {
		
		if(!errorMessage){
			JOptionPane.showMessageDialog(null, msg);
			errorMessage = true;
			}

	}
	
	/**
	 * Creates a hour class cursor
	 *
	 */
	public void setHourClassCursor() {
		Cursor hourglassCursor = new Cursor(Cursor.WAIT_CURSOR);
		setCursor(hourglassCursor);
		
	}

	/**
	 * Creates a normal cursor
	 *
	 */
	public void setNormalCursor() {
		Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
		setCursor(normalCursor);
		
	}
	
	/**
	 * Creates a hand cursor
	 *
	 */
	public void setHandCursor() {
		Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
		setCursor(handCursor);
	}
	
}  
